package com.siao.component
{
	import flash.display.StageDisplayState;
	import flash.events.Event;
	import flash.events.FocusEvent;
	import flash.events.FullScreenEvent;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.external.ExternalInterface;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.text.TextFieldType;
	import flash.text.TextFormat;
	import flash.utils.Dictionary;
	
	/**
	 * 使用Event.OPEN事件替换FocusEvent.FOCUS_IN
	 */
	[Event(name="open", type="flash.events.Event")]
	
	/**
	 * 使用Event.COMPLETE事件替换FocusEvent.FOCUS_OUT
	 */
	[Event(name="complete", type="flash.events.Event")]
	
	/**
	 * 通过JavaScript支持在WMODE设置为非WINDOW情况的文本输入
	 * @author SiaoLeon
	 */
	public class TextInput extends TextField
	{
		// -------------------------------------------------------------------------------------------------------- 静态常量
		
		// -------------------------------------------------------------------------------------------------------- 静态变量
		
		/**
		 * JavaScript控制器对象名
		 */
		public static const JAVASCRIPT_CONTROLLER:String = "FlashInputFieldController";
		
		/**
		 * 实例集合
		 */
		private static var Instances:Dictionary;
		
		/**
		 * 是否已经初始化
		 */
		private static var IsInited:Boolean;
		
		// -------------------------------------------------------------------------------------------------------- 静态方法
		
		// -------------------------------------------------------------------------------------------------------- 静态函数
		
		/**
		 * 初始化
		 */
		private static function Init():void
		{
			if (IsInited)
			{
				return;
			}
			
			Instances = new Dictionary();
			IsInited = true;
			
			if (ExternalInterface.available)
			{
				ExternalInterface.addCallback("TextInputCallBack", TextInputCallBack);
			}
		}
		
		/**
		 * JavaScript回调方法
		 * @param name 实例名称
		 * @param cmd 回调命令
		 * @param text 回调文本
		 */
		private static function TextInputCallBack(name:String, cmd:String, text:String):void
		{
			if (Instances[name] == null)
			{
				return;
			}
			
			(Instances[name] as TextInput).callback(cmd, text);
		}
		
		// -------------------------------------------------------------------------------------------------------- 属性
		
		private var _text:String;
		
		override public function get text():String
		{
			return (ExternalInterface.available) ? this._text : super.text;
		}
		
		override public function set text(value:String):void
		{
			this.call("setText", value);
			
			this._text = value;
			
			if (!ExternalInterface.available)
			{
				super.text = value;
			}
		}
		
		override public function set name(value:String):void
		{
			this.call("setName", value);
			
			if (Instances[this.name] != null)
			{
				delete Instances[this.name];
			}
			
			super.name = value;
			
			if (this.stage != null)
			{
				Instances[this.name] = this;
			}
			
			this.update();
		}
		
		override public function set x(value:Number):void
		{
			super.x = value;
			
			this.update();
		}
		
		override public function set y(value:Number):void
		{
			super.y = value;
			
			this.update();
		}
		
		override public function set width(value:Number):void
		{
			super.width = value;
			
			this.update();
		}
		
		override public function set height(value:Number):void
		{
			super.height = value;
			
			this.update();
		}
		
		override public function set selectable(value:Boolean):void
		{
			super.selectable = (ExternalInterface.available) ? false : value;
		}
		
		//		override public function set multiline(value:Boolean):void
		//		{
		//			super.multiline = (ExternalInterface.available) ? false : value;
		//		}
		
		//		override public function set wordWrap(value:Boolean):void
		//		{
		//			super.wordWrap = (ExternalInterface.available) ? false : value;
		//		}
		
		override public function set displayAsPassword(value:Boolean):void
		{
			super.displayAsPassword = value;
			
			this.update();
		}
		
		override public function set defaultTextFormat(format:TextFormat):void
		{
			super.defaultTextFormat = format;
			
			this.update();
		}
		
		override public function set maxChars(value:int):void
		{
			super.maxChars = value;
			
			this.update();
		}
		
		override public function set visible(value:Boolean):void
		{
			this.call((value) ? "show" : "hide");
			
			this.update();
			
			super.visible = value;
		}
		
		// -------------------------------------------------------------------------------------------------------- 变量
		
		// -------------------------------------------------------------------------------------------------------- 构造
		
		/**
		 * 构造函数
		 * @param name 实例名称
		 */
		public function TextInput(name:String)
		{
			super();
			
			Init();
			
			this.type = (ExternalInterface.available) ? TextFieldType.DYNAMIC : TextFieldType.INPUT;
			this.selectable = (this.type == TextFieldType.INPUT);
			this.multiline = this.wordWrap = false;
			this.name = name;
			this.height = 20;
			this.width = 200;
			this.text = "";
			
			this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage, false, 0, true);
		}
		
		// -------------------------------------------------------------------------------------------------------- 方法
		
		/**
		 * JavaScript回调方法
		 * @param cmd
		 * @param text
		 */
		public function callback(cmd:String, text:String):void
		{
			this._text = text;
			
			if (int(cmd) == 13)
			{
				this.dispatchEvent(new KeyboardEvent(KeyboardEvent.KEY_DOWN, true, false, 0, 13));
				return;
			}
			
			if (cmd == "focusIn")
			{
				this.dispatchEvent(new Event(Event.OPEN));
				return;
			}
			
			if (cmd == "focusOut")
			{
				this.dispatchEvent(new Event(Event.COMPLETE));
				return;
			}
		}
		
		/**
		 * 更新布局
		 */
		public function update():void
		{
			if (this.stage == null)
			{
				return;
			}
			
			var pt:Point = this.localToGlobal(new Point(0, 0));
			
			var text:String = this.text;
			var type:String = (this.displayAsPassword) ? "password" : "text";
			var maxChars:uint = (this.maxChars > 0) ? this.maxChars : int.MAX_VALUE;
			var x:Number = pt.x;
			var y:Number = pt.y;
			var width:Number = this.width;
			var height:Number = this.height;
			var font:String = this.defaultTextFormat.font;
			var size:Number = Number(this.defaultTextFormat.size);
			var color:String = "#" + this.defaultTextFormat.color.toString(16).toUpperCase();
			var leading:Number = Number(this.defaultTextFormat.leading);
			
			this.call("update", text, type, x, y, width, height, font, size, color, maxChars, leading);
		}
		
		// -------------------------------------------------------------------------------------------------------- 函数
		
		/**
		 * 添加到舞台时
		 * @param event
		 */
		private function onAddedToStage(event:Event):void
		{
			this.visible = this.type == TextFieldType.INPUT || !(this.stage.displayState == StageDisplayState.FULL_SCREEN || this.stage.displayState == StageDisplayState.FULL_SCREEN_INTERACTIVE);
			this.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
			
			this.addEventListener(FocusEvent.FOCUS_IN, onFocusIn, false, 0, true);
			this.addEventListener(FocusEvent.FOCUS_OUT, onFocusOut, false, 0, true);
			this.addEventListener(MouseEvent.CLICK, onMouseClick, false, 0, true);
			this.addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage, false, 0, true);
			this.stage.addEventListener(Event.RESIZE, onStageReszie, false, 0, true);
			this.stage.addEventListener(FullScreenEvent.FULL_SCREEN, onFullScreen, false, 0, true);
			
			this.create();
			
			this.update();
		}
		
		/**
		 * 从舞台移除时
		 * @param event
		 */
		private function onRemovedFromStage(event:Event):void
		{
			this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
			
			this.removeEventListener(FocusEvent.FOCUS_IN, onFocusIn);
			this.removeEventListener(FocusEvent.FOCUS_OUT, onFocusOut);
			this.removeEventListener(MouseEvent.CLICK, onMouseClick);
			this.removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
			this.stage.removeEventListener(Event.RESIZE, onStageReszie);
			this.stage.removeEventListener(FullScreenEvent.FULL_SCREEN, onFullScreen);
			
			this.remove();
		}
		
		/**
		 * 创建JavaScript文本输入框对象
		 */
		private function create():void
		{
			this.call("create", this.multiline ? "textarea" : "input");
			
			if (Instances[this.name] != null)
			{
				delete Instances[this.name];
			}
			
			Instances[this.name] = this;
		}
		
		/**
		 * 移除JavaScript文本输入框对象
		 */
		private function remove():void
		{
			this.call("remove");
			
			if (Instances[this.name] != null)
			{
				delete Instances[this.name];
			}
		}
		
		/**
		 * 同步
		 * @param event
		 */
		private function sync():void
		{
			if (this.stage && ExternalInterface.available)
			{
				this.stage.focus = null;
			}
			
			this.call("foucsIn");
		}
		
		/**
		 * 舞台缩放时
		 * @param event
		 */
		private function onStageReszie(event:Event):void
		{
			this.update();
		}
		
		/**
		 * 全屏切换时
		 * @param event
		 */
		private function onFullScreen(event:FullScreenEvent):void
		{
			this.visible = (this.type == TextFieldType.INPUT || !event.fullScreen || this.stage.displayState == StageDisplayState.FULL_SCREEN_INTERACTIVE);
		}
		
		/**
		 * 鼠标点击时
		 * @param event
		 */
		private function onMouseClick(event:MouseEvent):void
		{
			this.sync();
		}
		
		/**
		 * 焦点移入时
		 * @param event
		 */
		private function onFocusIn(event:Event):void
		{
			if (!ExternalInterface.available || this.stage.displayState != StageDisplayState.FULL_SCREEN)
			{
				this.sync();
			}
		}
		
		/**
		 * 焦点移出时
		 * @param event
		 */
		private function onFocusOut(event:Event):void
		{
			if (!ExternalInterface.available)
			{
				this.dispatchEvent(new Event(Event.COMPLETE));
			}
		}
		
		/**
		 * 调用JavaScript方法
		 * @param cmd 方法名称
		 * @param args 传入参数
		 */
		private function call(cmd:String, ... args):void
		{
			if (ExternalInterface.available)
			{
				var javascript:Function = ExternalInterface.call;
				args.unshift(JAVASCRIPT_CONTROLLER + "." + cmd, this.name);
				javascript.apply(null, args);
			}
		}
	}
}
